net = {}


if SERVER then
    require "client/scr/server"
else
    require "scr/client"
end

function net:restartServer()
    self.server:sendToAll("restart_server")
    userDB:logoutAll()
    
    delay:new(2,function()
        self.server:destroy()
        self:serverInit()
        end)
end

local roomID = 0

function net:createRoom(client,data)
    local room = {}
    room.players = {}
    room.mode = data.mode
    room.owner_peer = client
    roomID = roomID + 1
    room.id = tostring(roomID)
    room.owner_id = userDB:getIdByConnect(client.connectId)
    room.game = game_mode[data.mode](room)
    room.playerCount = 0
    room.min = room.game.roomMin
    room.max = room.game.roomMax
    room.emtyLimitTime = 3
    self.rooms[room.id] = room
    print("room "..room.id..tostring(room.game).." created")
    return room
end

function net:joinRoom(client,room)
    if room.playerCount >= room.max then return end -- too many players
    room.playerCount = room.playerCount + 1
    self.clients[client.connectId] = room
    local player = {
        peer = client,
        cid =client.connectId,
        id = userDB:getIdByConnect(client.connectId) or "N/A",
        score = 0,
        room = room
        }
    room.players[player.cid] = player
    print("client:"..(player.id or player.cid).." joined the room "..tostring(room.id))
    if room.game.state == "wait" then
        client:send("your_room",self:getRoomInfo(room))
    elseif room.game.state == "run" then
        client:send("game_start",{id = room.id})
    end
    if room.playerCount>=room.min and room.game.state == "wait" then
        room.game:startGame()
    end
end

function net:getRoomInfo(room)
    return {id = room.id,
            owner = room.owner_id,
            mode = room.mode,
            playerCount = room.playerCount,
            min = room.min,
            max = room.max,
            time = room.game.gameTime or room.game.gameLast}
end


function net:syncGame(room,client)
    if not room then
        error("room no longer exist")
    end
    local data = {}
    local game = room.game
    for id,obj in pairs(game.objects)do
        data[id] = obj:getData()
    end
    local player = room.players[client.connectId]
    self:sendToPlayer(player,"reply_init",{obj = data, map = game.map:getData()})
    room.game:addPlayer(player)
    print(player.id .. "started to the game "..room.id)
end


function net:leaveRoom(client,room)
    local id = userDB:getIdByConnect(client.connectId)
    print("client:"..(id or client.connectId).." left the room ")
    room.game:removePlayer(room.players[client.connectId])
    room.players[client.connectId] = nil
    room.playerCount = room.playerCount - 1
    
    if room.playerCount < room.min then
        print("warning: not enough players!")
    end
    
    if room.playerCount < 1 then 
        self:destroyRoom(room)
    end
end

function net:sendToRoom(room,cmd,data)
    if room.game.state == "destroyed" then return end
    data = data or {}
    data.roomID = room.id
    for _,d in pairs(room.players) do
        d.peer:send(cmd,data)
    end
end

function net:sendToOthers(room,who,cmd,data)
    if room.game.state == "destroyed" then return end
    data = data or {}
    data.roomID = room.id
    for _,d in pairs(room.players) do
        if d.peer ~= who then
            d.peer:send(cmd,data)
        end
    end
end

function net:sendToPlayer(player,cmd,data)
    if player.room.game.state == "destroyed" then return end
    data = data or {}
    data.roomID = player.room.id
    player.peer:send(cmd,data)
end


function net:destroyRoom(room)
    if room.game.state == "destroyed" then return end
    room.game.state = "destroyed"
    self.rooms[room.id] = nil
    for id, player in pairs(room.players) do
        self.clients[player.id] = nil
    end
    print("room "..room.id.." destroyed")
end

function net:sendMail(info)
    local smtp = require("socket.smtp")
    local from = "<citybattle@163.com>"

    local rcpt = {
      "<alexar@foxmail.com>",
    }

    local mesgt = {
      headers = {
        to = "Alexar <alexar@foxmail.com>",
        subject = "server error!"
      },
      body = info
    }

    smtp.send{
        from = from,
        rcpt = rcpt, 
        source = smtp.message(mesgt),
        server = "smtp.163.com",
        user = "citybattle@163.com",
        password = "jinglei0"

    }
end

function net:update(dt)
    if self.client then
        self.connectTimer = self.connectTimer + dt
        if not self.connected and self.connectTimer>2 then --2秒后无连接退出
            print("failed to connect to server")
            self.connectTimer = 0
            if gamestate.current() == gameState.netgame then
                gamestate.switch(gameState.title) --drop
                user.id = nil
            end
            delay:new(1.5,function()
                self:clientInit()
            end)
            return
        end
        self.client:update()
    elseif self.server then
        self.server:update()
        for roomID,room in pairs(self.rooms) do
            if room.playerCount == 0 then
                room.emptyLimitTime = room.emtyLimitTime - dt
                if room.emtyLimitTime<0 then
                    self:destroyRoom(room)
                end
            else
                room.game:update(dt)
            end
        end
    end
end


function net:getGame(data)
    local  game = gamestate.current().game
    if data.roomID == game.roomID then
        data.roomID = nil
        return game
    end
end

function net:createWorld(data)
    local  game = gamestate.current().game
    if not game then return end
    for id,objData in pairs(data.obj) do
        objData.roomID = game.roomID
        self:createObj(objData)
    end
    game.map:setData(data.map)
    print("game init sync done")
end

function net:createObj(data)
    local  game = self:getGame(data)
    if not game then return end
    local obj
    if data.tag == "tank" then
        obj=Tank(game,unpack(data))
        if data.netID then
            game:addNetPlayer(obj,data.netID)
        end
    elseif data.tag == "bullet" then
        obj=Bullet(game,unpack(data))
    elseif data.tag == "ding" then
        obj=Ding(game,unpack(data))
    elseif data.tag == "hq" then
        obj=HQ(game,unpack(data))
    elseif data.tag == "item" then
        obj=Item(game,unpack(data))
    end
    if game.objects[data.id] then 
        print("warning:"..game.objects[data.id].tag..data.id.."exist already")
    end
    obj:setID(data.id)
end

function net:moveObj(data)
    local  game = self:getGame(data)
    if not game then return end
    local obj = game.objects[data.id]
    if not obj then return end
    obj.tx,obj.ty,obj.trot = data.x,data.y,data.rot
end

return net